package org.springblade.metadata.service;

import java.io.BufferedReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Pattern;

import javax.annotation.PreDestroy;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;

import org.apache.atlas.AtlasBaseClient.API;
import org.apache.atlas.AtlasClientV2;
import org.apache.atlas.AtlasClientV2.API_V2;
import org.apache.atlas.AtlasServiceException;
import org.apache.atlas.model.discovery.AtlasSearchResult;
import org.apache.atlas.model.discovery.SearchParameters;
import org.apache.atlas.model.glossary.AtlasGlossary;
import org.apache.atlas.model.instance.AtlasEntity;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.raysdata.atlas.common.SystemConstant;
import com.sun.jersey.core.util.MultivaluedMapImpl;

import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class AtlasProxyService {
	//private String[] urls = new String[] { "http://10.10.3.115:21000" };
	private String[] urls ;
	private String name = "admin";
	private String pass = "admin";
	private AtlasClientV2 atlasClientV2 = null;
    
	private String gsname = "gids";
	private String gguid;
	private List<API_V2Url> apis = new ArrayList<API_V2Url>();
	
	
    public String getGguid() {
		return gguid;
	}
	public void setGguid(String gguid) {
		this.gguid = gguid;
	}
	@Autowired
	public AtlasProxyService(@Value("${atlas.url}") String[] urls ,@Value("${atlas.name}") String name , @Value("${atlas.name}") String pass, @Value("${atlas.gsname}") String gsname) {
		
    	if(StringUtils.isBlank(gsname)){
    		this.gsname = gsname;
    	} 
    	
    	SystemConstant.GLOSSARY_GTOUP_NAME  = this.gsname;
		this.urls = urls;
		this.name = name;
		this.pass = pass;
		atlasClientV2 = new AtlasClientV2(this.urls, new String[] { this.name, this.pass });
		Field[] fields = AtlasClientV2.API_V2.class.getFields();
		for (Field field : fields) {
			if (Modifier.isStatic(field.getModifiers())) {
				log.info("name : {} class :{}", field.getName(), field.getGenericType().toString());
				if ("class org.apache.atlas.AtlasClientV2$API_V2".equals(field.getGenericType().toString())) {
					try {
						AtlasClientV2.API_V2 api = (API_V2) AtlasClientV2.API_V2.class.getField(field.getName())
								.get(null);
						String pattern =null;
						log.info(api.getPath());
						if(api.getPath().contains("%s")) {
							 pattern = api.getPath().replaceAll("%s", "[A-Za-z0-9-]{1,50}");
						}else {
							if(api.getMethod().equals("GET")&& api.getPath().endsWith("/")) {
								pattern = api.getPath() + "[A-Za-z0-9-]{1,50}";
								
								api = new AtlasClientV2.API_V2(api.getPath()+"%s" ,HttpMethod.GET,Response.Status.OK);
							}else {
								pattern = api.getPath();
							}
						}

						log.info("pattern is: {} ", pattern);
						API_V2Url au = new API_V2Url();
						au.setApi(api);
						au.setUrl(pattern);
						String[] ss = api.getPath().split("/");
						au.setSs(ss);
						apis.add(au);
					} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException
							| SecurityException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}
		try {
			List<AtlasGlossary>  ags = atlasClientV2.getAllGlossaries("", 100, 0);
			log.info("test");
			ObjectMapper mapper = new ObjectMapper();
			
			List<AtlasGlossary> aggs = mapper.convertValue(ags,new TypeReference<List<AtlasGlossary> >(){});
			
			for(AtlasGlossary  ag :aggs) {
				if(ag.getName() .equals(this.gsname)) {
					gguid = ag.getGuid();
					log.info("group root id exit : " +gguid);
				}
			}
			
			if(StringUtils.isBlank(gguid)) {
				AtlasGlossary glossary = new AtlasGlossary();
				glossary.setName(gsname);
				glossary = atlasClientV2.createGlossary(glossary);
				this.gguid = glossary.getGuid();
				
				log.info("create group root id : " +gguid);
			}
		} catch (AtlasServiceException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
//		API_V2 GET_GLOSSARY_TERM  = new API_V2("api/atlas/v2/glossary/term/%s", HttpMethod.GET, Response.Status.OK);
//		
//		API_V2Url auGET_GLOSSARY_TERM = new API_V2Url();
//		auGET_GLOSSARY_TERM.setApi(GET_GLOSSARY_TERM);
//		auGET_GLOSSARY_TERM.setUrl("api/atlas/v2/glossary/term/[A-Za-z0-9-]{1,50}");
//		String[] ss = GET_GLOSSARY_TERM.getPath().split("/");
//		auGET_GLOSSARY_TERM.setSs(ss);
//		apis.add(auGET_GLOSSARY_TERM);
	}
     public AtlasClientV2 get() {
    	 return this.atlasClientV2;
     }
	API formatPathParameters(API api, String... params) {
		return new API(String.format(api.getPath(), params), api.getMethod(), api.getExpectedStatus());
	}

	// 字符串读取
	// 方法一
	public String ReadAsChars(HttpServletRequest request) {

		BufferedReader br = null;
		StringBuilder sb = new StringBuilder("");
		try {
			br = request.getReader();
			String str;
			while ((str = br.readLine()) != null) {
				sb.append(str);
			}
			br.close();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (null != br) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return sb.toString();
	}

	public String call(API_V2 api, HttpServletRequest request, String[] ss) throws AtlasServiceException, JsonMappingException, JsonProcessingException {
		
		
		if(api == API_V2.BASIC_SEARCH) {
			String body = ReadAsChars(request);
			SearchParameters params ;
			ObjectMapper objectMapper = new ObjectMapper();
			params= objectMapper.readValue(body, SearchParameters.class);
			return atlasClientV2.callAPI(formatPathParameters(api, ss), String.class, params);
		}
		
		Enumeration<String> parameterNames = request.getParameterNames();
		
		MultivaluedMap<String, String>  queryParams = new MultivaluedMapImpl();
		
		while (parameterNames.hasMoreElements()) {
		    String key = (String) parameterNames.nextElement();
		    String val = request.getParameter(key);
		    queryParams.add(key, val);
		}
		return atlasClientV2.callAPI(formatPathParameters(api, ss), String.class, queryParams);
	}

	public AtlasSearchResult callAPI(API_V2 api, String query, String[] ss) throws AtlasServiceException, JsonMappingException, JsonProcessingException {

		SearchParameters searchParameters = new SearchParameters();
		searchParameters.setQuery(query);
		return atlasClientV2.callAPI(formatPathParameters(api, ss), AtlasSearchResult.class, searchParameters);
	}

	public AtlasEntity callAPI(String guid) throws AtlasServiceException, JsonMappingException, JsonProcessingException {
		AtlasEntity             ret      = null;
		SearchParameters searchParameters = new SearchParameters();
		//searchParameters.setQuery(query);
		//return atlasClientV2.callAPI(formatPathParameters(api, ss), AtlasSearchResult.class, null);
		AtlasEntity.AtlasEntityWithExtInfo getByGuidResponse = atlasClientV2.getEntityByGuid(guid);
		ret = getByGuidResponse.getEntity();
		return ret;
	}


	public String[] extract(API_V2Url au, String url) {
		List<String> rs = new ArrayList<>();
		String[] froms = url.split("/");
		String[] us = au.getSs();
		for (int i = 0; i < us.length; i++) {
			if ("%s".equals(us[i])) {
				rs.add(froms[i]);
			}
		}
		String[] ss = new String[rs.size()];
		return rs.toArray(ss);
	}

	public API_V2Url getAPI(String url,String method) {

		for (API_V2Url au : apis) {
//			log.info("url: {}  method :{}",au.getUrl(),au.getApi().getMethod());
			if (Pattern.matches(au.getUrl(), url)) {
				if(au.getApi().getMethod().equals(method)) {
					return au;
				}
			}

		}

		return null;

	}

	@PreDestroy
	void destroy() {
		if (atlasClientV2 != null) {
			atlasClientV2.close();
		}
	}
}
